#ifndef CLUSTER_CONTROL_NETWORK_CONTROLLER_PATH_MANAGER_PATH_MANAGER_H_
#define CLUSTER_CONTROL_NETWORK_CONTROLLER_PATH_MANAGER_PATH_MANAGER_H_

#include <iostream>
#include <functional>
#include <vector>
#include <utility>
#include <unordered_map>

namespace ai_sim {

using EndComponentId = int;
using DeviceId = int;
using SrcDstPair = std::pair<EndComponentId, EndComponentId>;

struct pair_hash {
    template <class T1, class T2>
    std::size_t operator() (const std::pair<T1, T2> &pair) const {
        return std::hash<T1>()(pair.first) ^ std::hash<T2>()(pair.second);
    }
};

struct Connection {
    Connection(int _in_port_id, int _out_port_id) :
        in_port_id(_in_port_id), out_port_id(_out_port_id) {}
    int in_port_id;
    int out_port_id;

    bool operator==(const Connection& other) const {
        return ((in_port_id == other.in_port_id) &&
                (out_port_id == other.out_port_id));
    }
};

struct Relay {
    Relay(DeviceId _device_id, int _in_port_id, int _out_port_id) :
        device_id(_device_id), connection(_in_port_id, _out_port_id) {}
    DeviceId device_id;
    Connection connection;

    bool operator==(const Relay& other) const {
        return ((device_id == other.device_id) &&
                (connection == other.connection));
    }

    bool operator<(const Relay& other) const {
        return (device_id < other.device_id);
    }
};

struct ChangeSet {
    std::vector<Connection> config_to_add;
    std::vector<Connection> config_to_remove;
};

using Path = std::vector<Relay>;

class PathManager {
  public:
    virtual ~PathManager() {}
    virtual void AddPath(
        EndComponentId src, EndComponentId dst, const Path& path) = 0;
    virtual void RemovePath(EndComponentId src, EndComponentId dst) = 0;
    //  Release the change set after invoked
    virtual ChangeSet GetChangeSet(DeviceId device_id);

  protected:
    // record the changed new added connection of some device
    std::unordered_map<DeviceId, std::vector<Connection> > added_change_set_;
    // record the changed removed connection of some device
    std::unordered_map<DeviceId, std::vector<Connection> > removed_change_set_;
};

}  // namespace ai_sim

#endif  // CLUSTER_CONTROL_NETWORK_CONTROLLER_PATH_MANAGER_PATH_MANAGER_H_
